#include "actor.h"

//===============================================================
// Initializes a new actor at the specified position.
//===============================================================
CActor::CActor(int nX, int nY)
	: 	m_flSpeed(200),
		m_flMoveDistance(0), 
		m_nOffsetX(0), 
		m_nOffsetY(0),
		m_nPrevUpdate(0),
		m_bMoving(false),
		m_pMap(0),
		m_nDirection(DIR_DOWN),
		m_bRepeatMovement(false)
{
	m_nX = nX;
	m_nY = nY;
	strcpy(m_szName, "CActor");
}

//===============================================================
// Checks if its possible to move the actor 1 step into the specified direction.
//===============================================================
bool CActor::CanMove(int nDir) {
	if (!m_pMap)
		return false;
	
	int x = m_nX / 32;
	int y = m_nY / 32;
	
	switch ( nDir ) {
		case DIR_UP: y--; break;
		case DIR_RIGHT: x++; break;
		case DIR_DOWN: y++; break;
		case DIR_LEFT: x--; break;
	}
	
	TILEINFO *ti = m_pMap->GetTileInfo(x, y);
	if (ti) 
	{
		if (ti->flags & TF_DIRBLOCKED) 
		{
			unsigned char f = 0;
			switch (nDir) {
				case DIR_UP: f = TF_BLOCK_DOWN; break;
				case DIR_RIGHT: f = TF_BLOCK_LEFT; break;
				case DIR_DOWN: f = TF_BLOCK_UP; break;
				case DIR_LEFT: f = TF_BLOCK_LEFT; break;
			}

			return ((ti->flags & f) == 0);
		}
		else return ((ti->flags & TF_BLOCKED) == 0);
	}
	return false;
}

//===============================================================
// Moves the actor in the specified direction.
//===============================================================
void CActor::Move(int nDir) 
{
	if (m_bMoving || nDir < 0 || nDir >= DIR_NONE)
		return;

	m_nDirection = nDir;
	if (m_pAni) 
	{
		switch (m_nDirection) 
		{
			case DIR_UP: m_pAni->SetAnimation(3); break;
			case DIR_RIGHT: m_pAni->SetAnimation(2); break;
			case DIR_DOWN: m_pAni->SetAnimation(1); break;
			case DIR_LEFT: m_pAni->SetAnimation(0); break;
		}
	}

	if (!CanMove(nDir))
		return;

	m_flMoveDistance = 32;
	m_bMoving = true;
}

//===============================================================
// Stops moving the actor.
//===============================================================
void CActor::StopMovement()
{
	if (!m_bMoving)
		return;

	m_nX += m_nOffsetX;
	m_nY += m_nOffsetY;
	m_nOffsetX = m_nOffsetY = 0;

	m_bMoving = false;
}

//===============================================================
// Updates the position of the entity when its moving.
//===============================================================
void CActor::HandleMovement( int tick ) 
{
	if ( !m_bMoving )
		return;

	/* Calculate the distance that has been moved. */
    float dist = (m_flSpeed * (tick - m_nPrevUpdate)) / 1000;
    m_flMoveDistance -= dist;
	if (m_flMoveDistance < 0)
    {
        m_flMoveDistance = 0;
    }

    /* Update the current position. */
    switch (m_nDirection)
    {
        case DIR_UP: /* Move the actor up. */
            {
				m_nOffsetY = -((int)(32 - m_flMoveDistance));
                if (m_flMoveDistance == 0.0f)
                {
                    StopMovement();
                }
            }
            break;

        case DIR_RIGHT: /* Move the actor right. */
            {
				m_nOffsetX = (int)(32 - m_flMoveDistance);
                if (m_flMoveDistance == 0.0f)
                {
                    StopMovement();
                }
            }
            break;

        case DIR_DOWN: /* Move the actor down. */
            {
				m_nOffsetY = (int)(32 - m_flMoveDistance);
                if (m_flMoveDistance == 0.0f)
                {
                    StopMovement();
                }
            }
            break;

        case DIR_LEFT: /* Move the actor left. */
            {
				m_nOffsetX = -((int)(32 - m_flMoveDistance));
                if (m_flMoveDistance == 0.0f)
                {
                    StopMovement();
                }
            }
            break;
        }
}

//===============================================================
// Updates the actor.
//===============================================================
void CActor::Think( int tick ) 
{
	if (m_bMoving)
		HandleMovement( tick );
		
	m_nPrevUpdate = tick;	
}
